// new Compile(el, vm)

class Compile {
    constructor(el, vm) {
        // 要遍历的宿主元素
        this.$el = document.querySelector(el)

        this.$vm = vm

        // 编译（必须存在 el 才能）
        if(this.$el) {
            // 将 $el 里面的dom节点转成 片段，不直接操作dom元素
            // 这样操作的就是一个虚拟的东西，而不是真实的dom节点
            this.$fragment = this.node2Fragment(this.$el)
            // 执行编译
            this.compile(this.$fragment)
            // 将编译完的html追加至 $el
            this.$el.appendChild(this.$fragment)
        }
    }

    node2Fragment(el) {
        const frag = document.createDocumentFragment()
        // 将el中所有元素  移动  （也就是剪切） 到 frag中
        let child;
        while(child = el.firstChild) {
            // appendChild 是移动操作
            frag.appendChild(child)
        }
        return frag
    }
    // 编译过程
    compile(el){
        const childNodes = el.childNodes;
        Array.from(childNodes).forEach(node => {
            // 判断类型
            if(this.isElement(node)) {
                // 元素
                // console.log('编译元素' + node.nodeName)
                // 查找所有属性 找 k-vue  @ k-html ...
                const attrs = node.attributes;
                Array.from(attrs).forEach(attr => {
                    // console.log('==', attr) // k-test="name"
                    const attrName = attr.name // 属性名 k-test
                    const exp = attr.value // 属性值 name
                    // 指令
                    if(this.isDirective(attrName)) {
                        const dir = attrName.substring(2)
                        // 执行指令
                        this[dir] && this[dir](node, this.$vm, exp)
                    }
                    // 事件
                    if(this.isEvent(attrName)) {

                    }
                })
            }else if(this.isInterpolation(node)) {
                // 文本
                // console.log('编译文本' + node.textContent)
                this.compileText(node)
            }

            // 需要递归子节点
            if(node.childNodes && node.childNodes.length > 0){
                this.compile(node)
            }

        })
    }

    isDirective(attr){
        return attr.indexOf('k-') === 0
    }
    isEvent(attr) {
        return attr.indexOf('@') === 0
    }

    text(node, vm, exp){
        this.update(node, vm, exp, 'text')
    }

    isElement(node){
        return node.nodeType === 1
    }
    isInterpolation(node){
        // 需要找的是插值文本，而不是类似 ssf 这样的文本
        return node.nodeType === 3 && /\{\{(.*)\}\}/.test(node.textContent)
    }

    compileText(node){
        // console.log(RegExp.$1) // exp  插值的值 {{foo}}  foo
        // node.textContent = this.$options.data[RegExp.$1]
        // node.textContent = this.$vm.$data[RegExp.$1]
        this.update(node, this.$vm, RegExp.$1, 'text')
    }

    update(node, vm, exp, dir) {
        // dir 指的是 文本还是指令  text html module
        const updateFn = this[dir + 'Updater']
        // 初始化，第一次更新
        // ==> 要改成  vm[exp] 去掉  $data   属性，方法代理
        updateFn && updateFn(node, vm.$data[exp])
        // 以后还需要依赖收集
        new Watcher(vm, exp, function(value){
            updateFn && updateFn(node, value)
        })
    }
    //
    textUpdater(node, value) {
        node.textContent = value
    }
}